#!/usr/bin/perl
#diskman-lib.pl

use Data::Dumper;

do "../web-lib.pl";

&init_config();

%hwinfo=&hwinfo("diskman");
@ctrl=&get_ctrl_num ();
&foreign_require("mount", "mount-lib.pl");
&foreign_require("raid", "raid-lib.pl");
&foreign_require("fdisk", "fdisk-lib.pl");
&foreign_require("proc", "proc-lib.pl");

%access = get_module_acl();

#niu:get controller number - 3ware card only.
sub get_ctrl_num
{
	my (@ctrl_num);
	open(CTRLSHOW,"/sbin/tw_cli/tw_cli show 2>/dev/null |");
  @temp=<CTRLSHOW>;
  close(CTRLSHOW);
  foreach (@temp){
  		if($_ =~ /(c\d+)\s+/){
  			push(@ctrl_num,$1);
  			#`echo $1 >>/root/ctrl`;
  		}
  }
	return @ctrl_num;
}

sub check_istat()
{
	my $dev = $_[0];
	open(FI, "/etc/ietd.conf");
	@iet=<FI>;
	close(FI);
	foreach $it (@iet) {
		$it =~ s/\r|\n//g;
		if($it =~ /(\/dev\/\S+),Type/){
		   if($dev eq $1){
			return 1;
		   }
		}
	}
	return 0;
}
sub hwinfo
{
	my ($found,%hwinfo_cache);

	$found=0;

    
	if(-f '/proc/scsi/hptmv/0')
        {     
            $hwinfo_cache{'hotswap_support'}=1; 
        }
	open(FD,"/hwinfo")||die;
	while(<FD>){
		if( $_ =~ /^#/ ) { next; }
		if( $_ =~ /^\[$_[0]\]/ ) { $found=1; next; }
		if( $found ) {
			if( $_ =~ /(\S+)=(\S+)/ ) { $hwinfo_cache{$1}=$2; }	
		}
	}
	close(FD);
	return %hwinfo_cache;
}

sub get_diskindex
{

	my %sdinfo;

	open(SFDISK,"sfdisk -l|")||return undef;
	while(<SFDISK>){
		if(/Disk (\/dev\/sd[a-z]):/){
                        $sdinfo{&scsi_id($1)}=$1;
                }
        }
        close(SFDISK);

	my (@dinfo,$scsiid,$device,$index);

	$index=0;

	open(DISKINFO,$config{'diskinfo'})||return undef;
	while(<DISKINFO>){
		s/\r|\n//g;
		s/#.*$//g;
		if (/(\S+)\s*=\s*(\S+)\s+(\S+)/) {
			$device = $1;
			$status = $2;
			$scsiid = $3;

			$index++; 

			$dinfo[$index-1]->{'name'}   = 'disk'.$index;
			$dinfo[$index-1]->{'status'} = $status;
			$dinfo[$index-1]->{'scsiid'} = $scsiid;

			if ($scsiid =~ /\d+,\d+,\d+,\d+/) { 
				$dinfo[$index-1]->{'device'} = $sdinfo{$scsiid};
			} else {
				$dinfo[$index-1]->{'device'} = $device;
			}
			
		}
	}
	close(DISKINFO);
	return @dinfo;
}

# rdev2disk(\dinfo, rdev)
# return the diskname of rdev
sub rdev2disk
{
	my ($df, $rdev)=@_;
	my $index=0;
	
	$rdev =~ s/\d+$//;
	
	foreach $d (@{$df}) {
		if ($d->{'device'} eq $rdev) {
			if ( $d->{'name'} =~ /disk(\d+)/ ) { $index=$1;}
			last;
		}
	}
	return $index;
}

# diskname2rdev(\dinfo, diskname)
# return the dev path of diskname
sub diskname2rdev
{
	my ($df, $diskname)=@_;
	my $rdev;

	foreach $d (@{$df}) {
		if ($d->{'name'} eq $diskname) {
			$rdev=$d->{'device'};
			last;
		}
	}
	return $rdev;
}

sub is_usrvol
{
	return 1;
}


sub get_usrvol_name
{
	return "volume1";
}

#cm:get disk infomation for hardraid system - 3ware card only.
#return an array of diskinfo
sub new_get_diskinfo
{
        my($i, $line, $disk_num, $scsiid, $device, $status, $index, $type);
        my($diskid,$capacity, $raidid, $style);
        my(@sys_diskpart_info,$d,$found,$sdfound,$userpart,@parts,$p,@stat);
        $disk_num = $hwinfo{'diskn'};
        for ($i = 0; $i < $disk_num; $i++) {
                $diskinfo_cache[$i]->{'name'} = 'disk'.($i+1);
		$diskinfo_cache[$i]->{'device'} = 'p'.$i;
                $diskinfo_cache[$i]->{'status'} = 'NOT-PRESENT';
		$diskinfo_cache[$i]->{'capacity'} = '-';
		$diskinfo_cache[$i]->{'raidid'} = '-';
		$diskinfo_cache[$i]->{'style'} = '-';
        }
      	$index=-1;

	#get the status of disks from diskinfo(file)
	#open(DISKINFO, '/$ctrl[0]');
        open(DISKINFO, "/sbin/tw_cli/tw_cli /$ctrl[0] show 2>/dev/null |");
        while($line = <DISKINFO>) {
       	$line =~ s/\r|\n//g;
           $line =~ s/#.*$//g;
           if (($line =~ /(p\d+)\s+(\S+)\s+(\S*)\s+(\S*\s\S+)\s+(\S*)\s+(\S*)/)||($line =~ /(p\d*)\s+(\S+)\s+(\S*)\s+(\S*)\s+(\S*)\s+(\S*)/)){
              
              $device = $1;
              $status = $2;
              $capacity = $4;
              $raidid = $3;
	      $sty = `/sbin/tw_cli/tw_cli /$ctrl[0]/$device show model 2>/dev/null`;
              $sty =~ /Model\s+=\s+(.*)/;
              $style = $1;

              $index++;    
           }else{
              next;
           }
		$device =~ /p(\d+)/;
		$idx = $1;
           $diskinfo_cache[$idx]->{'device'} = $device;
           $diskinfo_cache[$idx]->{'status'} = $status;
           $diskinfo_cache[$idx]->{'raidid'} = $raidid;
           $diskinfo_cache[$idx]->{'capacity'} = $capacity;
           $diskinfo_cache[$idx]->{'style'} = $style;
        }
        close(DISKINFO);
	return @diskinfo_cache;
}

##cm: get raid info for hard raid - 3ware card only
sub new_get_check_raid_info
{
	my ($hrdinfo, @lsraid_info);
        $volroot = "/usrvol/";
        $hrdinfo = \@raidinfo_cache;
        $cmd = $config{'amccpath'}." /$ctrl[0]"." show 2>/dev/null |";
        open(LSRAID, $cmd);
        while($line= <LSRAID>){
            if($line =~ /^(u\d*)\s+(\S+)\s+(\S+)\s+(\S*)\s+(\S*)\s+(\S+)\s+(\S+)/){          
                $hrdinfo->[$i]->{'name'} = $1;
                $ux = $hrdinfo->[$i]->{'name'};
                $hrdinfo->[$i]->{'raidlevel'} =$2;
                $hrdinfo->[$i]->{'status'}= $3;
                $hrdinfo->[$i]->{'size'} = $7;
                $hrdinfo->[$i]->{'percent'} = $4;
                $perc = $hrdinfo->[$i]->{'percent'};
                if($perc eq '-'){
                   $hrdinfo->[$i]->{'recovery'} = 0;
                }else{
                   $hrdinfo->[$i]->{'recovery'} = 1;
                }
                $hrdinfo->[$i]->{'volname'} = get_volname($1);
                $hrdinfo->[$i]->{'voldir'} = $volroot.$hrdinfo->[$i]->{'volname'};
                $hrdinfo->[$i]->{'disks'} = get_unit_disks($ux);
                ($dq, $wd) = get_unitinfo($ux);
                $hrdinfo->[$i]->{'raid_disks'} = $dq;
                $hrdinfo->[$i]->{'working_disks'} = $wd;
                $i++;
            }else{
                next;
            }
        }
        close(LSRAID);
        return @raidinfo_cache; 
}

# new_has_free_disk()
# if has free disk that can created in a volume, return 1;
# otherwise return 0 ---------------ChenMo
sub new_has_free_disk
{
    open(FREED, "/sbin/tw_cli/tw_cli /$ctrl[0] show 2>/dev/null |");
    @freedisk = <FREED>;
    close(FREED);
    foreach (@freedisk)
    {
       if($_ =~ /^(p\d*)\s+OK\s+-/){
          return 1;
       }
    }
    return 0;
}

# get_free_volumes(rdinfo)
# return an array of free volumes' names that can be created
sub get_free_volumes
{
	my ($rf, $max_volume, $i, @vol_status, @free_volumes);

	@free_volumes = ();
	$rf = $_[0];
	$max_volume = $hwinfo{'max_volume'};

	for ($i = 0; $i < $max_volume; $i++) {
		$vol_status[$i] = 0;	#0: free; 1:used
	}

	my ($r);
	foreach $r (@{$rf}) {
		#all usrvol(include 'normal' and 'unknown') has a valid volname
		if ($r->{'volname'} =~ /diskarray(\d+)/) {
			if ($1 <= $max_volume && $1 > 0) {
				$vol_status[$1 - 1] = 1;
			}
		}
	}

	for ($i = 0; $i < $max_volume; $i++) {
		if ($vol_status[$i] == 0) {
			push(@free_volumes, "diskarray".($i+1));
		}
		#else is a bug
	}

	return @free_volumes;
}

# new_get_free_disks()
# return an array of free disks name that can be added to a new volume
# By ChenMo 2005.11.22
sub new_get_free_disks
{
    my ($df, $d, @free_disks);
    @free_disks = ();
    open(FREED, "/sbin/tw_cli/tw_cli /$ctrl[0] show 2>/dev/null |");
    @temp=<FREED>;
    close(FREED);
    foreach (@temp){
       if($_ =~ /^(p\d*)\s+OK\s+-/){
          push(@free_disks, $1); 
       }
    }
    return @free_disks;
 
}


# get_free_disks(dinfo)
# return an array of free disks' name (such as disk1, disk2 etc.)
# that an be added to a volume
sub get_free_disks
{
	my ($df, $d, @free_disks);

	@free_disks = ();
	$df = $_[0];

	foreach $d (@{$df}) {
		if ($d->{'status'} eq 'well' && $d->{'using'} eq 'unused') {
				push(@free_disks, $d->{'name'});
		}
	}
	return @free_disks;
}

# new_create_volume($level, \@rdevs, $volname, $mddev, $sparedev)
# for 3w hardraid controller only!
# if success, return 0; else return 1 
sub new_create_volume
{
    my ($level, $rdf, $volname, $mddev, $sparedev, $out, $diskcap);
    $type = $_[0];
    if($_[0] =~ /^linear/){
       $level = "single";
    }else{
       $level = "raid".$_[0];
    }
    $diskcap = $_[5];
    my $disk;
    my @disklist = split(/\s+/, $_[1]);
    my $i = 0;
    foreach(@disklist){
       if($_ =~ /^p(\d*)/){
         if($i == 0){
            $disk .= $1; 
         }else{
            $disk .= ":".$1;
         } 
       }
       $i++;
    }

    my $scsinum = 1;
    #-------------------------------------------------------------------# 
    $volname = $_[2];
    `/sbin/tw_cli/tw_cli /$ctrl[0] set autocarve=off 2>/dev/null`;
    sleep(3);
    $out = `/sbin/tw_cli/tw_cli /$ctrl[0] add type=$level disk=$disk name=$volname`; 
    my $result = $?;   
    `rm -f /var/nas/lock/mkfsd_new`;
    return $result;
}

sub get_free_volnames
{
  #@vname=();
  $lvnum = $_[0];
  @lvinfo = get_lv_info();
  @volnames = ("volume1", "volume2", "volume3", "volume4", "volume5", "volume6", "volume7", "volume8", "volume9");
     for($rr=0,$idx=0; $rr<9,$idx<$lvnum; $rr++) {
         $found = 0; 
         foreach $lv (@lvinfo) {
            if ($lv->{'volname'} eq $volnames[$rr]) {
                $found = 1; last;
            }
         }
         if($found){
            next;
         }
         else{
            $volnames[$rr] =~ /\S(\d)/;
            push(@vname, $volnames[$rr]); 
            $idx++;
         }
     }
     return @vname;
}
sub update_sd
{
   my $initdev = $_[0];
   $initdev =~ /sd(\S)/;
   $letter = $1;
   $letter = $letter + 1;
   return "/dev/sd".$letter;
}

sub write_stale_config
{
}
sub read_stale_raid_config
{
	return @raid_info;
}
sub read_stale_disk_config
{
	return @disk_info;
}

# check_lock
# If the the init_script "ezusrvolcheck.pl" is running, return 1;
# If the mkfsd pid is running, return 2;
# else return 0.
sub check_lock
{
	my $rc;

	$rc = 0;
	if ( -s $config{'fsck_lock'} ) {
		open(MKFSD, $config{'fsck_lock'});
		my $fsckd_pid;
		$fsckd_pid = <MKFSD>;
		$fsckd_pid =~ s/\r|\n//g;
		$out = `kill -0 $fsckd_pid`;
		if ($?) {
			#not exit fsckd process
			$out = `rm -f $config{'mkfs_lock'}`;
			#keep $rc to 0, check mkfsd again.
		}
		else {
			$rc = 1;
		}
	}
	if ($rc) {
		return $rc;
	}

	if ( -s $config{'mkfs_lock'} ) {
		open(MKFSD, $config{'mkfs_lock'});
		my $mkfsd_pid;
		$mkfsd_pid = <MKFSD>;
		$mkfsd_pid =~ s/\r|\n//g;
		$out = `kill -0 $mkfsd_pid`;
		if ($?) {
			#not exit mkfsd process
			#
			$out = `rm -f $config{'mkfs_lock'}`;
		}
		else {
			$rc = 2;
		}
	}
	return $rc;
}
sub new_can_migrate
{
	#return 1 if raid can be migrated; else return 0;
	my $r = $_[0];
	if ($r->{'raid_disks'} ne $r->{'working_disks'}) {
		return 0;  #Not good raid.
	}
	if ($r->{'status'} ne "OK") {
		return 0;
	}
	if (($r->{'raidlevel'} ne "RAID-0") && ($r->{'raidlevel'} ne "RAID-5")){
		return 0;
	}
	my $freedisk = new_has_free_disk();
	if(!$freedisk){
		return 0;
	}
	return 1;
}
# chenmo: new function new_can_recovery
# check if a volume can be recoveried
# return 1, if the raid can be recovery; else return 0
sub new_can_recovery
{
        my $r = $_[0];   #parm 1, refer to the volume, eg 'u0';

        if ($r->{'raid_disks'} == $r->{'working_disks'}) {
                # good raid
                return 0;
        }
	my $freemark = new_has_free_disk();
        if (($r->{'status'} eq 'DEGRADED') && ($freemark == 1)){
                return 1;
        }
        
        return 0;
}


sub mounton
{
	$mount=0;

	open(MOUNT,"mount |");
	while(<MOUNT>){
		if(/$_[0] on $_[1]/) { $mount=1;last;}
	}
	close(MOUNT);
	return $mount;
}

sub scsi_id
{
	$line=`scsi_info $_[0] 2>/dev/null`;
	if($line =~ /SCSI_ID="(\d+,\d+,\d+,\d+)"/) {
		return $1;
	}
	return undef;
}

sub get_volname
{   
    $temp = $config{'amccpath'}." /$ctrl[0]/".$_[0]." show name 2>/dev/null |";
    open(AMCC, $temp);
    @amcc=<AMCC>;
    close(AMCC);
    foreach(@amcc){
       if($_ =~ /=\s(\S+)/){
           return $1;
       }
    }
}

## for 3ware raid controller, get the disks included in a unit, eg. u0
## return a array of disks eg {-, p2, p3}
sub get_unit_disks
{
   my @udisks;
   $temp = $config{'amccpath'}." /$ctrl[0]/".$_[0]." show 2>/dev/null |";
   open(UNIT, $temp);
   @unit=<UNIT>;
   close(UNIT);
   foreach(@unit)
   {
    if($_ =~ /^(u\d)\s+(\S+)\s+(\S+)\s+\S*\s+\S*\s+(\S*)\s+/){
       if(($2 eq 'SINGLE') && ($4 =~ /^-/)){
          #print "N/A(F) ";
          push(@udisks, "N/A(F)");
       }
       if(($2 eq 'SINGLE') && ($4 =~ /^(p\d*)/)){
          #print trpname($1)."(G) ";
          #push(@udisks, $1);
          push(@udisks, trpname($1)."(G)");
       }
    }

    if($_ =~ /^(u\d-\d*)\s+(\S+)\s+(\S+)\s+\S*\s+\S*\s+(\S*)\s+/){
       if($4 =~ /^-/){
          #print "N/A(F) ";
          push(@udisks, "N/A(F)");
       }else{
          #print trpname($4)."(G) ";
          #push(@udisks, $4)
          push(@udisks, trpname($4)."(G)");
       }
    }     
   }
   return @udisks;
}
#--------------------------#
# TRANSFER 'p0' to 'disk1' #
#--------------------------#
sub trpname
{
   if($_[0]=~/^p(\d*)/){
      $a=$1+1;

      return "D".$a;
   }
}
#-----------------------------------------#
# The following subs are used for  rewrite 
# unit scsi device config file:
# /etc/nas/sdinfo
#-----------------------------------------#
sub get_scsi_dev
{
   my @sd;
   open(SCSI, "fdisk -l /dev/sd* 2>/dev/null |");
   @scsidev = <SCSI>;
   close(SCSI);
   foreach(@scsidev)
   {
     if($_ =~ /^Disk\s\/dev\/sd(\S):/)
     {
       #print $1;
       push(@sd, $1);
     }
   }
   return @sd;
}

#-----------------------------------------------------#
# Get the first scsiid, such as 'sda','sdb', that is  
# not used by system.
#-----------------------------------------------------#
sub get_free_scsi_dev
{
   @cap = (a,b,c,"d","e","f","g","h","i","j");
   @scsid=get_scsi_dev();
   foreach(@cap)
   {
      $ca = $_;
      $found = 0;
      foreach(@scsid)
      {
         if($_ eq $ca)
         {
            $found = 1;
            last;
         }
      }
      if(!$found){
         #print "|".$ca."\n";
         return "/dev/sd".$ca;
         last;
      }
   }

}

sub get_free_scsi_devs
{
   $num = $_[0];
   @cap = (a,b,c,"d","e","f","g","h","i","j");
   @scsid=get_scsi_dev();
   $ee = 0;
   for ($uu=0,$ee=0; $uu<10,$ee<$num; $uu++) {
      $ca = $cap[$uu];
      $found = 0;
      foreach(@scsid){
          if($_ eq $ca){
             $found = 1; 
          }
      }
      if($found){
         next;
      }
      else
      { 
        $sdev[$ee] = '/dev/sd'.$ca;
        $ee++;
      }
   }
   return @sdev;
}
#------------------------------------------------#
# Get the unit id num that is not used by now in #
# system. Return such as 'u0', 'u1'...           #
#------------------------------------------------#
sub get_free_unit
{  
   $cmdtmp = $config{'amccpath'}." /$ctrl[0] show 2>/dev/null |";
   open(FU, $cmdtmp);
   @units=<FU>;
   close(FU);
   for($i=0; $i<16; $i++)
   {
      $foundu = 0;
      $index = $i;
      foreach(@units)
      {
        if($_ =~ /^u(\d*)\s+/){
           if($1 eq $index){
              $foundu = 1;
              last;
           }
        }
      }
      if(!$foundu){
         return "u".$index;
         last;
      }
   }

}


# Get the device used by ux 
# parm is the unit name,such as 'u0'
# return the device, such as '/dev/sda' 
sub get_scsidev
{
   $unitname = $_[0];
   @capt = (a, b, c, d, e, f, g, h, i, j, k, l, "m", n, o, p);
   if($unitname =~ /^u(\d)/){
       $ca = $capt[$1];
       $devname = '/dev/sd'.$ca;
   }
   return $devname;
}

sub get_unitinfo
{
   $ux=$_[0];
   $cmd = $config{'amccpath'}." /$ctrl[0]/".$ux." show 2>/dev/null |";
   open(FC, $cmd);  @uinfo = <FC>;  close(FC);
   $ii=0;  $jj=0;
   foreach(@uinfo){
      $line = $_;
      if($line =~ /^$ux\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+/){
         $type = $1;    $stat = $2;     $perc = $3;     $port = $4;
         if($type eq 'SINGLE'){
            $ii = 1; $jj = 1;
            return ($ii, $jj);
         }
      }
      if($line =~ /^($ux-\S*)\s+(\S+)\s+(\S+)/){
         if($2 eq 'DISK'){
           $ii++;
           if($3 eq 'OK'){ $jj++; }
         }
      }
   }
   return ($ii, $jj);
}

sub get_pv_info()
{
        my @pvinfo=();
        my @pvinfob;
        my ($pv, $vg, $line);
        open(PV, "lvm pvs --noheadings --unit g 2>/dev/null |");
        my $i = 0;
        while($line = <PV>) {
                $line =~ s/\r|\n//g;
                $line =~ s/#.*$//g;
                if ($line =~ /\s+(\S+)\s+(\S+)\s+\S+\s\S+\s+(\S+)G\s+(\S+)G/) {
                        $pv = $1;
                        $vg = $2;
                        $i++;
                        $pvinfo[$i]->{'pv'} = $pv;
                        $pvinfo[$i]->{'vg'} = $vg;
                }
                elsif ($line =~ /\s+(\S+)\s+\S+\s+(\S+)\s+(\S+)G\s+(\S+)G/) {
                        $pv = $1;
                        $vg = "";
                        $i++;
                        $pvinfo[$i]->{'pv'} = $pv;
                        $pvinfo[$i]->{'vg'} = $vg;
                }
                elsif($line =~ /\s+(\S+)\s+(\S+)\s+\S+\s\S+\s+(\S+)G\s+0/){
                        $pv = $1;
                        $vg = $2;
                        $i++;
                        $pvinfo[$i]->{'pv'} = $pv;
                        $pvinfo[$i]->{'vg'} = $vg;
                }
                else{
                        next;
                }
        }
        close(PV);
        foreach $pvi (@pvinfo) {
                if($pvi->{'pv'}){
                        push(@pvinfob, $pvi);
                }
        }
        return @pvinfob;
}
1;
